package nl.rug.snitter;
import java.io.IOException;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.*;

import com.google.gson.Gson;

import nl.rug.snitter.message.ExtendedMessage;
import nl.rug.snitter.message.Message;
import nl.rug.snitter.site.CommonSiteCommands;
import nl.rug.snitter.site.ErrorResponse;
import nl.rug.snitter.site.LogInResponse;
import nl.rug.snitter.site.SimpleUserInfo;
import nl.rug.snitter.site.UserCreatingResponse;
import nl.rug.snitter.user.User;

@SuppressWarnings("serial")
public class SnitterServlet extends HttpServlet {
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException 
	{
//		PersistenceManager pm = PMF.get().getPersistenceManager(); 
//		resp.setContentType("text/plain");
//		try 
//		{
//			resp.getWriter().println("creating user");
//			User user= new User("Test 1", "Bla", "CCCCC", "quess it", "te_@da.com");
//			pm.makePersistent(user);
//			resp.getWriter().println("user is saved");
//			resp.getWriter().println("reading user");
//			String query= "select from " + User.class.getName();
//			List<User> users = (List<User>) pm.newQuery(query).execute();
//			for(User tempUser : users)
//			{
//				resp.getWriter().println("<<<>>>>");
//				resp.getWriter().println("name: " + tempUser.getName());
//				resp.getWriter().println("id: " + tempUser.getId());
//			}
//			resp.getWriter().println("done");
//			resp.getWriter().println("deleting db");
//			CommonDbCommands.clearDb();
//			resp.getWriter().println("done");
//		} 
//		finally 
//		{
//			pm.close();
//		}
		//resp.setContentType("text/plain");
		//resp.getWriter().println("Hello, world");
		//CommonDbCommands.clearDb();
//		resp.setContentType("text/plain");
//		resp.getWriter().println("creating user");
//		Long id;
//		Long id2;
//		User user1= new User("Test 1", "Bla1", "CCCCC1", "quess it 1", "te1_@da.com");
//		CommonDbCommands.AddUser(user1);
//		user1.setEmail("te1-1_@da.com");
//		CommonDbCommands.UpdateUser(user1);
//		@SuppressWarnings("unused")
//		User u2= CommonDbCommands.getUser(user1.getId(), true, true, null);
//		id= user1.getId();
//		resp.getWriter().println("done");
//		resp.getWriter().println("creating user 2");
//		User user2= new User("Test 2", "Bla2", "CCCCC2", "quess it 2", "te2_@da.com");
//		CommonDbCommands.AddUser(user2);
//		id2= user2.getId();
//		resp.getWriter().println("done");
//		resp.getWriter().println(id);
//		resp.getWriter().println(id2);
//		resp.getWriter().println("adding follower");
//		User userTemp= CommonDbCommands.findUserBy("name", "\"Test 1\"", true, true);
//		//User userTemp= CommonDbCommands.findUserBy("id", Long.toString(id), true, true);
//		//User userTemp= CommonDbCommands.getUser(user1.getId(), true, true, null);
//		CommonDbCommands.AddFollowerToUser(userTemp, id2);
//		resp.getWriter().println("done");
//		//CommonDbCommands.clearDb();
//		
//		resp.setContentType("text/plain");
//		User user3= CommonDbCommands.findUserBy("name", "\"Test 1\"", true, true);
//		User user4= CommonDbCommands.findUserBy("name", "\"Test 2\"", true, true);
//		resp.getWriter().println(user3.getFollowing().get(0));
		
//		adding msg testing
//		resp.setContentType("text/plain");
//		resp.getWriter().println("creating user");
//		User user1= new User("Test 1", "Bla1", "CCCCC1", "quess it 1", "te1_@da.com");
//		CommonDbCommands.AddUser(user1);
//		Message msg= new Message("basdajrari-aifdiafi=af\najdfajfra raafksaf\nafijafjasffawrwirfaj faojas f\nThe end!!", "My first msg");
//		CommonDbCommands.AddMessageToUser(user1, msg);
//		User user2= CommonDbCommands.findUserBy("name", "\"Test 1\"", true, true);
//		resp.getWriter().println("done");
		//CommonDbCommands.clearDb();
		
//		posting new msg test
//		resp.setContentType("text/plain");
//		resp.getWriter().println("creating user");
//		User user1= new User("Test 1", "Bla1", "CCCCC1", "quess it 1", "te1_@da.com");
//		CommonDbCommands.AddUser(user1);
//		User user2= new User("Test 2", "Bla2", "CCCCC2", "quess it 2", "te2_@da.com");
//		CommonDbCommands.AddUser(user2);
//		CommonDbCommands.AddFollowerToUser(user1, user2.getId(), null);
//		user2= CommonDbCommands.getUser(user2.getId(), true, true, null);
//		Message msg= new Message("basdajrari-aifdiafi=af\najdfajfra raafksaf\nafijafjasffawrwirfaj faojas f\nThe end!!", "My first msg");
//		CommonDbCommands.AddMessageToUser(user2, msg);
//		User user3= CommonDbCommands.findUserBy("name", "\"Test 1\"", true, true);
//		User user4= CommonDbCommands.findUserBy("name", "\"Test 2\"", true, true);
//		resp.getWriter().println("done");
		//CommonDbCommands.clearDb();
		
		
		// parse the url
		String answer= req.getParameter("command");
		if(answer != null)
		{
			if(answer.equals("deleteAll"))
			{
				CommonSiteCommands.deleteDB();
				resp.setContentType("text/plain");
				resp.getWriter().println("Db deleted");
			}
			else if(answer.equals("logIn"))
			{
				String email= req.getParameter("email");
				try
				{
					String pw= getMD5(req.getParameter("psw"));
					if(email != null && !email.equals(""))
					{
						User user= CommonSiteCommands.getUser(parseString(email));
						if(user != null)
						{
							if(user.getPassword().equals(pw))
							{
								LogInResponse login= new LogInResponse(user.getId());
								sendResponse(resp, login);
							}
							else
							{
								ErrorResponse error= new ErrorResponse("No user found", "No email or password found");
								sendResponse(resp, error);
							}
						}
						else
						{
							ErrorResponse error= new ErrorResponse("No user found", "No email or password found");
							sendResponse(resp, error);
						}
					}
					else
					{
						ErrorResponse error= new ErrorResponse("Empty field", "The email field may not be empty");
						sendResponse(resp, error);
					}
				}
				catch (NoSuchAlgorithmException e)
				{
					e.printStackTrace();
					ErrorResponse error= new ErrorResponse("Encoding error", "Couldn't encode the password");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("createUser"))
			{
				String email= req.getParameter("email");
				if(email != null && !email.equals(""))
				{
					User user= CommonSiteCommands.getUser(parseString(email));
					if(user == null)
					{
						try
						{
							user= new User();
							user.setEmail(email);
							user.setPassword(getMD5(req.getParameter("psw")));
							user.setAdress(req.getParameter("adress"));
							user.setName(req.getParameter("name"));
							user.setScreenName(req.getParameter("screenName"));
							user.setZipCode(req.getParameter("zipCode"));
							CommonSiteCommands.addUser(user);
							UserCreatingResponse rep= new UserCreatingResponse("User has been created");
							sendResponse(resp, rep);
						}
						catch (NoSuchAlgorithmException e)
						{
							e.printStackTrace();
							ErrorResponse error= new ErrorResponse("Encoding error", "Couldn't encode the password");
							sendResponse(resp, error);
						}
					}
					else
					{
						ErrorResponse error= new ErrorResponse("User already exists", "Can't create the user because another user was found with that email");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("Empty field", "The email field may not be empty");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getMsgFrom")) //get the last n messages from user
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						User user= CommonSiteCommands.getUser(id);
						int numberOfMsg= req.getParameter("nMsg") == null ? 5 : Integer.parseInt(req.getParameter("nMsg"));
						ArrayList<Long> msgs= user.getMessageManager().getMessages();
						int startIndex= numberOfMsg > msgs.size() ? 0 : msgs.size() - numberOfMsg;
						List<Long> msgIds= msgs.subList(startIndex , msgs.size());
						ArrayList<ExtendedMessage> finalMsg= new ArrayList<ExtendedMessage>();
						Message tempMsg= null;
						User tempUser= null;
						for(Long tempId : msgIds)
						{
							tempMsg= CommonSiteCommands.getMsg(tempId);
							if(tempMsg != null)
							{
								tempUser= CommonSiteCommands.getUser(tempMsg.getUserId());
								if(tempUser != null)
								{
									finalMsg.add(new ExtendedMessage(tempMsg, tempUser.convertToSimpleUserInfo()));
								}
							}
						}
						sendResponse(resp, finalMsg);
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getFollowersFrom"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						User user= CommonSiteCommands.getUser(id);
						sendResponse(resp, user.getFollowedBy());
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getFollowing"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						//User user= CommonSiteCommands.getUser(id);
						//sendResponse(resp, user.getFollowing());
						sendResponse(resp, CommonSiteCommands.getFollowingOfUser(id));
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("addFollowing"))
			{
				if(req.getParameter("id") != null)
				{
					long id= Long.parseLong(req.getParameter("id"));
					if(req.getParameter("idUserToFollow") != null)
					{
						try
						{
							long idUserToFollow= Long.parseLong(req.getParameter("idUserToFollow"));
							boolean hasBeenAdded= CommonSiteCommands.addFollowing(id, idUserToFollow);
							if(hasBeenAdded)
							{
								sendResponse(resp, "User added");
							}
							else
							{
								sendResponse(resp, new ErrorResponse("Couldn't follow the user", "You are allready following this user"));
							}
						}
						catch (NumberFormatException e)
						{
							ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
							sendResponse(resp, error);
						}
					}
					else
					{
						ErrorResponse error= new ErrorResponse("Empty field", "To follow user id may not be empty");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("Empty field", "User id may not be empty");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("addMsg"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						User user= CommonSiteCommands.getUser(id);
						String msg= req.getParameter("msg");
						String title= req.getParameter("msgTitle");
						Long msgId= null;
						if(msg != null)
						{
							if(!msg.equals(""))
							{
								if(title != null)
								{
									if(req.getParameter("msgTitle") == "")
									{
										msgId= CommonSiteCommands.saveMsg(user, msg, "Untitled");
										CommonSiteCommands.addMsgToUser(user, msgId);
										//CommonSiteCommands.addMsgToUser(user, msg, "Untitled");
										sendResponse(resp, "Message has been added");
									}
									else
									{
										msgId= CommonSiteCommands.saveMsg(user, msg, title);
										CommonSiteCommands.addMsgToUser(user, msgId);
										//CommonSiteCommands.addMsgToUser(user, msg, title);
										sendResponse(resp, "Message has been added");
									}
								}
								else
								{
									msgId= CommonSiteCommands.saveMsg(user, msg, "Untitled");
									CommonSiteCommands.addMsgToUser(user, msgId);
									//CommonSiteCommands.addMsgToUser(user, msg, "Untitled");
									sendResponse(resp, "Message has been added");
								}
							}
							else
							{
								ErrorResponse error= new ErrorResponse("No empty field allowed", "The message was empty");
								sendResponse(resp, error);
							}
						}
						else
						{
							ErrorResponse error= new ErrorResponse("No empty field allowed", "The message was empty");
							sendResponse(resp, error);
						}
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("removeMsg"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						User user= CommonSiteCommands.getUser(id);
						if(req.getParameter("msgNumber")!= null)
						{
							CommonSiteCommands.removeMsg(user, Long.parseLong(req.getParameter("msgNumber")));
							sendResponse(resp, "Message was deleted");
						}
						else
						{
							ErrorResponse error= new ErrorResponse("No index found", "No index was sent to be processed");
							sendResponse(resp, error);
						}
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getUserSimpleInfo"))
			{
				if(req.getParameter("id") != null)
				{
					Boolean removeNewMsgFrom= null;
					if(req.getParameter("masterUser") == null)
					{
						removeNewMsgFrom= false;
					}
					else
					{
						try
						{
							removeNewMsgFrom= Boolean.parseBoolean((req.getParameter("masterUser")));
						}
						catch (Exception e)
						{
							e.printStackTrace();
							removeNewMsgFrom= false;
						}
					}
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						User user= CommonSiteCommands.getUser(id);
						if(removeNewMsgFrom == true)
						{
							user.clearNewMsgFrom();
							CommonSiteCommands.updateUser(user);
						}
						sendResponse(resp, user.convertToSimpleUserInfo());
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("No id found", "No id was sent to be processed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("removeFollowing"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						if(req.getParameter("idUserFollowing") != null)
						{
							try
							{
								long idUserFollowing= Long.parseLong(req.getParameter("idUserFollowing"));
								CommonSiteCommands.removeFollowing(id, idUserFollowing);
								sendResponse(resp, "User removed");
							}
							catch (NumberFormatException e)
							{
								ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
								sendResponse(resp, error);
							}
						}
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("Empty field", "The id may not be empty");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("search"))
			{
				String searchBy= req.getParameter("searchBy");
				String searchFor= req.getParameter("searchFor");
				ArrayList<SimpleUserInfo> users= null;
				if(searchBy != null && searchFor != null)
				{
					if(searchBy.equals("userEmail"))
					{
						users= CommonSiteCommands.search("email", parseString(searchFor));
						if(users == null)
						{
							ErrorResponse error= new ErrorResponse("Internal error", "Couldn't execute request");
							sendResponse(resp, error);
						}
						else
						{
							sendResponse(resp, users);
						}
					}
					else if(searchBy.equals("screenName"))
					{
						users= CommonSiteCommands.search("screenName", parseString(searchFor));
						if(users == null)
						{
							ErrorResponse error= new ErrorResponse("Internal error", "Couldn't execute request");
							sendResponse(resp, error);
						}
						else
						{
							sendResponse(resp, users);
						}
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("Empty field", "No empty search parameters allowed");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getUserNewMsgList"))
			{
				if(req.getParameter("id") != null)
				{
					try
					{
						long id= Long.parseLong(req.getParameter("id"));
						long startId= -1;
						int size= -1;
						if(req.getParameter("startId") != null)
						{
							startId= Long.parseLong(req.getParameter("startId"));
						}
						if(req.getParameter("size") != null)
						{
							size= Integer.parseInt(req.getParameter("size"));
						}
						User user= CommonSiteCommands.getUser(id);
						sendResponse(resp, CommonSiteCommands.getListOfNewMsg(size < 0 ? 5 : size , startId, user));
					}
					catch (NumberFormatException e)
					{
						ErrorResponse error= new ErrorResponse("Unknown number format", "The id number was in a incorrect format");
						sendResponse(resp, error);
					}
				}
				else
				{
					ErrorResponse error= new ErrorResponse("Empty field", "The id may not be empty");
					sendResponse(resp, error);
				}
			}
			else if(answer.equals("getPublicNewMsgList"))
			{
				int size= -1;
				if(req.getParameter("size") != null)
				{
					size= Integer.parseInt(req.getParameter("size"));
				}
				sendResponse(resp, CommonSiteCommands.getPublicNewMsgList(size < 0 ? -1 : size));
			}
			else
			{
				resp.setContentType("text/plain");
				resp.getWriter().println("nothing has been done :(");
			}
		}
		else
		{
			resp.setContentType("text/plain");
			resp.getWriter().println("nothing has been done-2 :(");
		}
	}
	
	private void sendResponse(HttpServletResponse resp, Object obj) throws IOException
	{
		Gson gson= new Gson();
		resp.setContentType("text/plain");
		resp.getWriter().println(gson.toJson(obj));
	}
	
	private String parseString(String str)
	{
		String newStr= new String(str);
		if(!str.startsWith("\""))
		{
			newStr= "\"" + newStr; 
		}
		if(!str.endsWith("\""))
		{
			newStr= newStr + "\""; 
		}
		return newStr;
	}
	
	private String getMD5(String str) throws NoSuchAlgorithmException
	{
		MessageDigest m= MessageDigest.getInstance("MD5");
		m.reset();
		m.update(str.getBytes());
		byte[] digest= m.digest();
		BigInteger bigInt= new BigInteger(1, digest);
		String hashText= bigInt.toString(16);
		// Now we need to zero pad it if you actually want the full 32 chars.
		while(hashText.length() < 32 )
		{  
			hashText = "0"+hashText;
		}
		return hashText;
	}
}
